package com.llt.system.service.sysuser.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.llt.common.core.constants.HttpConstants;
import com.llt.common.core.domain.LoginUser;
import com.llt.common.core.domain.R;
import com.llt.common.core.enums.ResultCode;
import com.llt.common.core.enums.UserIdentity;
import com.llt.common.security.exception.ServiceException;
import com.llt.common.security.service.TokenService;
import com.llt.system.domain.sysuser.dto.SuserQueryDTO;
import com.llt.system.domain.sysuser.dto.SysUserSaveDTO;
import com.llt.system.domain.sysuser.po.SysUser;
import com.llt.system.domain.sysuser.vo.LoginUserVO;
import com.llt.system.domain.sysuser.vo.SysUserVO;
import com.llt.system.domain.user.dto.UserQueryDTO;
import com.llt.system.domain.user.vo.UserVO;
import com.llt.system.mapper.sysuser.SysUserMapper;
import com.llt.system.mapper.user.UserMapper;
import com.llt.system.service.sysuser.ISysUserService;
import com.llt.system.utils.BCryptUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author llt
 * @since 2024-08-06
 */
@Slf4j
@Service
@RefreshScope
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Value("${jwt.secret}")
    private String secret;

    private final SysUserMapper sysUserMapper;


    private final TokenService tokenService;

    @Override
    public R<String> login(String userAccount, String password) {
        log.info("正在登录......");
        
        // 1. 通过账号查询用户信息
        SysUser user = this.lambdaQuery()
                .select(SysUser::getUserId, SysUser::getUserName ,SysUser::getPassword)
                .eq(SysUser::getUserAccount, userAccount)
                .one();

        // 2. 用户不存在
        if (user == null) {
            return R.fail(ResultCode.FAILED_USER_NOT_EXISTS);
        }

        // 3. 验证正确
        if (BCryptUtils.matchesPassword(password, user.getPassword())) {
            String token = tokenService.createToken(user.getUserId(), secret, UserIdentity.ADMIN.getValue(), user.getUserName(), null);
            return R.ok(token);
        }

        // 4. 密码错误

        return R.fail(ResultCode.FAILED_LOGIN);
    }

    @Override
    public boolean add(SysUserSaveDTO dto) {
        // 1. 参数校验
        // todo

        // 2. 判断是否已经存在
        List<SysUser> list = this.lambdaQuery()
                .eq(SysUser::getUserAccount, dto.getUserAccount())
                .list();
        if (CollectionUtil.isNotEmpty(list)) {
            // 2.1 自定义异常(用户已存在)
            throw new ServiceException(ResultCode.AILED_USER_EXISTS);
        }

        // 3. 将 dto 转为 po
        SysUser user = new SysUser();
        user.setUserAccount(dto.getUserAccount());
        user.setPassword(BCryptUtils.encryptPassword(dto.getPassword()));

        // 4. 插入数据
        boolean save = this.save(user);

        return save;
    }

    @Override
    public R<LoginUserVO> info(String token) {
        // 1. 判断 token 是否有前缀
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }

        // 2. 从 redis 中获取到用户信息
        // 2.1 先从令牌中拿到 userKey, 再拼接成 key, 最后从 redis 中取
        LoginUser loginUser = tokenService.getLoginUser(token, secret);
        if (loginUser == null) {
            return R.fail();
        }

        // 3. 封装 VO 返回
        LoginUserVO vo = new LoginUserVO();
        vo.setUserName(loginUser.getUserName());

        return R.ok(vo);
    }

    @Override
    public R<Void> logout(String token) {
        log.info("正在退出登陆......");
        // 1. 判断 token 是否有前缀
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }

        // 2. 从 redis 中获取到用户信息
        // 2.1 先从令牌中拿到 userKey, 再拼接成 key, 最后从 redis 中删
        boolean delete = tokenService.delete(token, secret);
        if (!delete) {
            return R.fail();
        }
        return R.ok();
    }

    @Override
    public List<SysUserVO> list(SuserQueryDTO dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        return sysUserMapper.selectUserList(dto);
    }
}
